package com.anxin.registerManagement.filter;

import com.alibaba.fastjson.JSONObject;
import com.anxin.registerManagement.util.Const;
import com.anxin.registerManagement.util.ResultUtil;
import com.anxin.registerManagement.util.jwt.JwtToken;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


/**
 * @author 叶前呈
 * @date 2022/1/23 17:51
 */
@Component
public class JwtFilter extends BasicHttpAuthenticationFilter {

    private static Logger logger = LoggerFactory.getLogger(JwtFilter.class);

    /**
     * 执行登录认证
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        //如果请求头不存在token,则可能是执行登陆操作或是游客状态访问
        //新生报到管理系统不存在游客状态访问，因此，不含token直接返回false
        if (isLoginAttempt(request, response)) {
            // 返回 true 表示 直接放行，不去执行token登录操作
            // 返回 false 则所有不带token请求 jwt 过滤器处理的url 会直接报错
            return false;
        }
        //如果存在,则进入executeLogin方法执行登入,检查token 是否正确
        // 返回 false的话 就不会继续往下执行权限判断的部分
        return executeLogin(request, response);
    }


    /**
     * 重写AuthenticatingFilter的executeLogin方法丶执行登陆操作
     * 进行token的验证
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) {
        //在请求头中获取token
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(Const.jwtName); //前端命名Authorization
        JwtToken jwtToken = new JwtToken(token);
        // 提交给realm进行登入，如果错误它会抛出异常并被捕获
        try {
            getSubject(request, response).login(jwtToken);
        } catch (Exception e) {
            logger.warn("token认证出错：{}", e.getMessage());
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;

            httpServletResponse.setStatus(HttpStatus.OK.value());
            httpServletResponse.setContentType("application/json;charset=UTF-8");
            try {
                PrintWriter writer = httpServletResponse.getWriter();
                writer.write(JSONObject.toJSONString(ResultUtil.fail(Const.ERROR_JWT_TOKEN)));
                writer.flush();
            } catch (IOException ex) {
                logger.error(ex.getMessage());
            }
            return false;
        }
        return true;
    }

    /**
     * 判断用户是否想要登入。
     * 检测 header 里面是否包含 token 字段
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest req = (HttpServletRequest) request;
        String token = req.getHeader(Const.jwtName);
        return token != null;
    }
}
